<?php
/**
 * Copyright (c) 2022-2222   All rights reserved.
 *
 * 创建时间：2022-11-04 12:17
 *
 * 项目：levs  -  $  - ModelRankv.php
 *
 * 作者：liwei
 */

//!defined('INLEV') && exit('Access Denied LEV');


namespace lev\base;

use Lev;

class ModelRankv extends Modelv
{

    public static function typeidArr() {
        return [
            0 => '用户',
            1 => '汇总',
            2 => 'IP',
            3 => '页面',
        ];
    }

    public static function tstatusArr()
    {
        return [
            0 => '未统计',
            1 => '<absxn>已统计</absxn>',
        ];
    }

    /**
     * @return array
     */
    public static function ranktypeArr() {
        return [
            0 => '天榜',
            1 => '周榜',
            2 => '月榜',
            3 => '年榜',
            4 => '总榜',
        ];
    }

    public static function rankdateArr($timestamp) {
        return [
            0 => date('Ymd', $timestamp),//每天 => 天榜
            1 => date('Y0W', $timestamp),//每周 => 周榜
            2 => date('Ym', $timestamp),//每月 => 月榜
            3 => date('Y', $timestamp),//每年 => 年榜
            4 => 0,//总和 => 总榜
        ];
    }

    /**
     * 同时统计总量和总数。可根据实际情况，指定不同统计单位
     * 也可以在用户操作同时 更新 排名总数
     * @param $uid
     * @param $typeid
     * @param $addtotal
     * @param int $addnum
     * @param int $ranktime
     * @param int $addwintotal
     * @param int $addwinnum
     */
    public static function updateRankv($uid, $typeid, $addtotal, $addnum = 1, $ranktime = 0, $addwintotal = 0, $addwinnum = 0) {
        !$ranktime && $ranktime = Lev::$app['timestamp'];

        $rankdates = static::rankdateArr($ranktime);
        $pudata = [
            'uid'    => $uid,
            'typeid' => $typeid,
            'uptime' => Lev::$app['uptime'],
        ];
        $myRanks = static::myRanksv($uid, $typeid, $ranktime);
        foreach ($rankdates as $k => $datex) {
            $updata = $pudata;
            if (isset($myRanks[$datex])) {
                $updata['totalnum'] = $myRanks[$datex]['totalnum'] + $addnum;
                $updata['totalwinnum']  = $myRanks[$datex]['totalwinnum'] + $addwinnum;
                $updata['totals'] = $myRanks[$datex]['totals'] + $addtotal;
                $updata['totalswin']  = $myRanks[$datex]['totalswin'] + $addwintotal;

                $updata['totals'] &&
                $updata['totalswinrate'] = round($updata['totalswin']/$updata['totals'] * 1000);
                $updata['totalnum'] &&
                $updata['totalwinrate'] = round($updata['totalwinnum']/$updata['totalnum'] * 1000);

                static::update($updata, ['id' => $myRanks[$datex]['id']]);
            } else {
                $updata['totalwinnum']  = $addwinnum;
                $updata['totalswin']  = $addwintotal;
                $updata['totals'] = $addtotal;
                $updata['totalnum'] = $addnum;
                $updata['ranktype'] = $k;
                $updata['rankdate'] = $datex;
                $updata['addtime'] = Lev::$app['timestamp'];
                static::insert($updata);
            }
        }
    }

    public static function myRanksv($uid, $typeid = null, $ranktime = 0) {
        !$ranktime && $ranktime = Lev::$app['timestamp'];

        $rankdates = static::rankdateArr($ranktime);

        $where['uid'] = $uid;
        $insql = implode(',', $rankdates);
        $where[] = "rankdate IN ($insql)";
        $typeid !== null && $where['typeid'] = $typeid;
        $myRanks = static::findAll($where, 'rankdate');
        return $myRanks;
    }

    /**
     * 统计
     * 根据实际情况，重写此方法
     * @param null $modalObject
     * @param array $where
     * @param array $update
     * @param int $limit
     * @param string $astatusField
     * @param string $totalsField
     * @param string $totalswinField
     * @param string $totalnumField
     * @param string $totalwinnumField
     * @param string $field
     * @return array|bool
     */
    public static function statisticsv($modalObject = null, $where = ['tstatus'=>0], $update = ['tstatus'=>1], $limit = 2000, $astatusField = 'astatus', $totalsField = 'score', $totalswinField = 'awardscore', $totalnumField = '', $totalwinnumField = '', $field = '*') {
        if ($errMsg = Lev::actionOnce(static::tableName().'_statistics')) return $errMsg;

        $totals = 0;
        $result['uid']['total'] = [
            'totals' => 0,
            'totalswin' => 0,
            'totalnum' => 0,
            'totalwinnum' => 0,
        ];

        //$limit = 2000;
        //$where['tstatus'] = 0;
        $fisrt = $modalObject::findOneByOrder($where, ['id ASC'], $field);
        if (!$fisrt) return Lev::responseMsg(-2, '统计完成');

        $etime = strtotime(date('Y-m-d', $fisrt['addtime']).' 00:00:00') + 3600*24;
        $where[] = 'addtime>='.$fisrt['addtime'];
        $where[] = 'addtime<'.$etime;
        $where[] = 'id<'.($fisrt['id'] + $limit);
        $lists = $modalObject::findAll($where, '', [], $field);
        foreach ($lists as $v) {
            $vastatus = !empty($v[$astatusField]);
            $vtotals = isset($v[$totalsField]) ? $v[$totalsField] : 1;
            $vtotalswin = isset($v[$totalswinField]) ? $v[$totalswinField] : 1;
            $vtotalnum = isset($v[$totalnumField]) ? $v[$totalnumField] : 1;
            $vtotalwinnum = isset($v[$totalwinnumField]) ? $v[$totalwinnumField] : 1;
            $totals += $vtotals;
            $result['uid']['total']['totalnum'] += $vtotalnum;
            $result['uid']['total']['totals']  += $vtotals;
            $result['uid']['total']['totalswin'] += $vtotalswin;
            $censusKeyArr['uid'] = $v['uid'];
            if (isset($v['ip'])) {
                $censusKeyArr['ip'] = $v['ip'];
            }
            if (isset($v['pagename'])) {
                $censusKeyArr['pagename'] = $v['pagename'];
            }
            foreach ($censusKeyArr as $tkey => $censusKey) {
                if (!isset($result[$tkey][$censusKey]['totalnum'])) {
                    $result[$tkey][$censusKey]['totals'] = 0;
                    $result[$tkey][$censusKey]['totalswin'] = 0;
                    $result[$tkey][$censusKey]['totalnum'] = 0;
                    $result[$tkey][$censusKey]['totalwinnum'] = 0;
                }
                $result[$tkey][$censusKey]['totalnum'] += $vtotalnum;
                if ($vastatus) {
                    $result[$tkey][$censusKey]['totalwinnum'] += $vtotalwinnum;
                    $result[$tkey]['total']['totalwinnum'] += $vtotalwinnum;
                }

                $result[$tkey][$censusKey]['totals'] += $vtotals;
                $result[$tkey][$censusKey]['totalswin'] += $vtotalswin;
            }
            $modalObject::update($update, ['id'=>$v['id']]);
        }
        if ($result) {
            foreach ($result as $tkey => $vr) {
                foreach ($vr as $uid => $v) {
                    if ($tkey === 'uid') {
                        $typeid = $uid === 'total' ? 1 : 0;
                    }else if ($tkey === 'ip') {
                        $typeid = 2;
                    }else if ($tkey === 'pagename') {
                        $typeid = 3;
                    }
                    static::updateRankv($uid, $typeid, $v['totals'], $v['totalnum'], $fisrt['addtime'], $v['totalswin'], $v['totalwinnum']);
                }
            }
        }
        $count = count($lists);
        $ck = $count>=$limit || $etime < Lev::$app['timestamp'];
        $tip = !$ck ? ' => 统计完成' : ' => 统计中...';
        return Lev::responseMsg(1, '本次共统计'.$count.'条数据，'.count($result).'个类型。'.date('Ymd', $fisrt['addtime']).$tip, [
            'ck'=>$ck,
            'totals' => $totals,
            'result' => $result,
        ]);
    }

    public static function headerRankHtm($tmpPath) {
        $route = $tmpPath.'/statisticsv';
        $typeids = static::typeidArr();
        $as = '';
        foreach ($typeids as $id => $name) {
            $as .= '<a class="button button-fill button-small color-blackg" href="'.Lev::toReRoute([$tmpPath, 'typeid'=>$id]).'">'.$name.'</a>';
        }
        $tod = date('Ymd', Lev::$app['timestamp']);
        $ysd = date('Ymd', Lev::$app['timestamp'] - 3600 * 24);
        $as .= '<a class="button button-fill button-small color-black" href="'.Lev::toCurrent(['rankdate'=>$tod]).'">今天</a>';
        $as .= '<a class="button button-fill button-small color-black" href="'.Lev::toCurrent(['rankdate'=>$ysd]).'">昨天</a>';
        return '<div class="card card-header">
                    <ol class="ol-cm">
                    <li>请手动点击统计，每次统计2000条。</li>
                    <li><div class="buttons-row">'.$as.'</div></li>
                    </ol>
                    <div class="buttons-row scale9">
                        <a class="button button-fill button-small openPP" href="'.Lev::toReRoute([$route]).'">执行统计</a>
                    </div>
                </div>';
    }

    public static function createRankTableSql($iden, $tableName = '') {
        !$tableName && $tableName = '{{%'.$iden.'_ranks}}';
        $tableOptionsMyISAM = static::setMyISAMtableOptions();
        return <<<EOF
            
    CREATE TABLE IF NOT EXISTS `$tableName` (
    `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
    `typeid` bigint NOT NULL DEFAULT '0' COMMENT '分类排名',
    `uid` varchar(80) NOT NULL DEFAULT '0' COMMENT '统计用户UID',
    `ranktype` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '排名类型',
    `rankdate` int UNSIGNED NOT NULL DEFAULT '0' COMMENT '排名周期',
    `totals` bigint(20) NOT NULL DEFAULT '0' COMMENT '总数量',
    `totalswin` bigint(20) NOT NULL DEFAULT '0' COMMENT '胜总数量',
    `totalswinrate` int NOT NULL DEFAULT '0' COMMENT '胜率',
    `totalnum` bigint(20) NOT NULL DEFAULT '0' COMMENT '总次数',
    `totalwinnum` bigint(20) NOT NULL DEFAULT '0' COMMENT '胜总次数',
    `totalwinrate` int NOT NULL DEFAULT '0' COMMENT '次胜率',
    `settings` mediumtext NOT NULL COMMENT '通用设置',
    `uptime` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '更新时间',
    `addtime` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '添加时间',
    PRIMARY KEY (`id`),
    UNIQUE KEY `rankdate_uid_typeid` (`rankdate`,`uid`,`typeid`),
    KEY `typeid` (`typeid`),
    KEY `uid` (`uid`),
    KEY `totalnum` (`totalnum`),
    KEY `totalwinnum` (`totalwinnum`),
    KEY `totalwinrate` (`totalwinrate`)
    ) $tableOptionsMyISAM;

EOF;

    }

}